import Module from "./Module"
import * as THREE from "three"
import o from "../math/45870"
import CameraModule from "./CameraModule"
import ViewmodeData from "../data/ViewmodeData"
import InteractionmodeData from "../data/InteractionmodeData"
import g from "../packages/76870"
import { BeginSwitchViewmodeMessage } from "../message/viewmode.message"
import { DragBeginEvent, DragEndEvent, DragEvent } from "../event/DragEvent"
import { KeyEvent } from "../event/KeyEvent"
import CommonControlsModule from "./CommonControlsModule"
import SettingsData from "../data/SettingsData"
import SymbolList from "../SymbolList"
import keyConst from "../constant/key.const"
import hotKeyEnum, { KeyState } from "../enum/hotKey.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import PanoramaCameraControls from "../controls/PanoramaCameraControls"
import EngineContext from "../EngineContext"
import InputIniModule from "./InputIniModule"
import MarketContext from "../MarketContext"
export default class PanoramaControlsModule extends Module {
  controlsEngaged: boolean
  lookAccelerationSpeed: number
  calcRotationAngle: (n: any, r: any, o: any) => THREE.Vector2
  controls: PanoramaCameraControls
  market: MarketContext
  constructor() {
    super(...arguments)
    this.name = "panorama-controls"
    this.controlsEngaged = !1
    this.lookAccelerationSpeed = o.WI
    this.calcRotationAngle = (() => {
      const e = new THREE.Matrix4(),
        t = new THREE.Vector3(),
        i = new THREE.Vector3()
      return (n, r, o) => {
        const a = n.getData(!1)
        e.copy(a.pose.projection.asThreeMatrix4()), e.invert(), t.set(r.x - o.x, r.y - o.y, -1).applyMatrix4(e), i.set(r.x, r.y, -1).applyMatrix4(e)
        const l = Math.sqrt(t.x * t.x + t.z * t.z),
          c = Math.sqrt(i.x * i.x + i.z * i.z),
          h = Math.atan2(t.y, l),
          d = Math.atan2(i.y, c) - h
        ;(t.y = 0), (i.y = 0), t.normalize(), i.normalize()
        const u = Math.acos(t.dot(i))
        let p = 0
        return isNaN(u) || ((p = u), o.x > 0 && (p *= -1)), new THREE.Vector2(-p, -d)
      }
    })()
  }
  async init(e, t: EngineContext) {
    const i = await t.getModule(CameraModule)
    this.controls = new PanoramaCameraControls(i)
    ;(await t.getModule(CommonControlsModule)).addControls(viewmodeEnum.Panorama, this.controls)
    this.market = t.market
    this.bindings.push(
      t.subscribe(BeginSwitchViewmodeMessage, e => {
        this.controls.stop()
      })
    )
    t.getModuleBySymbol<InputIniModule>(SymbolList.INPUT).then(e => {
      e.registerHandler(DragBeginEvent, e => {
        this.validateViewmode() && this.controls.stop()
      })
      e.registerHandler(DragEvent, e => {
        this.validateViewmode() &&
          e.buttons & g.r3.PRIMARY &&
          ((this.controlsEngaged = !0), this.onDrag(i, e.position, e.delta), this.controls.update(o.SI), this.controls.stop())
      })
      e.registerHandler(DragEndEvent, e => {
        this.validateViewmode() &&
          this.controlsEngaged &&
          (e.timeSinceLastMove < 100 &&
            !(e.buttons & g.r3.PRIMARY) &&
            (this.onDrag(i, e.position, e.delta), this.controls.update(o.SI), this.controls.setLookAcceleration({ x: 0, y: 0 })),
          (this.controlsEngaged = !1))
      })
      e.registerHandler(KeyEvent, e => {
        this.validateViewmode() && this.onKey(e.key, e.state)
      })
    })
  }
  onUpdate(e) {
    this.validateViewmode() && this.controls.update(e)
  }
  onDrag(e, t, i) {
    this.controls.setLookAcceleration(this.calcRotationAngle(e, t, i))
  }
  onKey(e, t) {
    let i = null
    const n = this.market.tryGetData(SettingsData)
    n && (i = n.tryGetProperty(keyConst.lookAccelerationKey, null)), (this.lookAccelerationSpeed = i ? (i * (Math.PI / 180)) / 60 : this.lookAccelerationSpeed)
    const s = t === KeyState.DOWN
    switch (e) {
      case hotKeyEnum.LEFTARROW:
      case hotKeyEnum.J:
        this.controls.setLookAcceleration({ x: s ? this.lookAccelerationSpeed : 0 }, !0)
        break
      case hotKeyEnum.RIGHTARROW:
      case hotKeyEnum.L:
        this.controls.setLookAcceleration({ x: s ? -this.lookAccelerationSpeed : 0 }, !0)
        break
      case hotKeyEnum.K:
        this.controls.setLookAcceleration({ y: s ? -this.lookAccelerationSpeed : 0 }, !0)
        break
      case hotKeyEnum.I:
        this.controls.setLookAcceleration({ y: s ? this.lookAccelerationSpeed : 0 }, !0)
    }
  }
  validateViewmode() {
    const e = this.market.tryGetData(ViewmodeData)
    const t = this.market.tryGetData(InteractionmodeData)
    return !e || !t || (e.isInside() && !t.isVR())
  }
}
